﻿//----------------------------------------------------------------------------------------------------
// The Game Rule Manager is responsible for victory and defeat processing
//----------------------------------------------------------------------------------------------------

package HG.Managers
{
	import HG.Debug;
	
	import HG.GameService;
	import HG.Managers.LevelManager;
	import HG.Managers.PlayerManager;
	import HG.Managers.NotificationManager;
	
	import HG.Visual.VisualNode;
	
	import HG.GameTypes.*;
	
	import HG.Events.GameEvent;
	import HG.Events.PlayerEvent;
	import HG.Events.NodeEvent;
	
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	import HG.Events.LevelEvent;
	import HG.GameDataTypes.Player;
	
	public class GameRuleManager extends IGameManager
	{
		public static var FATE_UNKNOWN:Number = 0;
		public static var FATE_DEFEAT:Number = 1;
		public static var FATE_VICTORY:Number = 2;
		
		public static var GAMETYPE_NORMAL:Number = 0;
		public static var GAMETYPE_RUSH:Number = 1;
		
		var m_levelManager:LevelManager;
		var m_playerManager:PlayerManager;
		var m_notificationManager:NotificationManager;
		
		var m_numGoalNodes:Number;
		var m_numDocuments:Number;
		var m_numNodes:Number;
		
		var m_capMap:Array;
		var m_fateMap:Array;
		var m_docMap:Array;
		var m_killMap:Array;
		
		var m_gEvt:GameEvent;
		
		var m_editor:Boolean;
		
		var m_gameTypes:Array;
		var m_currentGameType:Number;
		
		//----------------------------------------------------------------------------------------------------
		public override function GameRuleManager()
		{
			m_editor = false;
			
			m_gameTypes = new Array();
			
		}
		
		//----------------------------------------------------------------------------------------------------
		public override function Initialize()
		{
			m_levelManager = GameService.GetInstance().GetLevelManager();
			m_playerManager = GameService.GetInstance().GetPlayerManager();
			m_notificationManager = GameService.GetInstance().GetNotificationManager();
			
			m_levelManager.addEventListener(NodeEvent.SPAWN, OnNodeSpawned);
			m_levelManager.addEventListener(LevelEvent.LOAD, OnLevelLoaded);
			m_levelManager.addEventListener(LevelEvent.UNLOAD, OnLevelUnLoaded);
			
			m_levelManager.addEventListener(NodeEvent.CAPTURE, OnNodeCaptured);
			m_playerManager.addEventListener(PlayerEvent.JOIN, OnPlayerJoin);
			
			
			// Setup gametypes.
			m_gameTypes[GAMETYPE_NORMAL] = new GameType_Normal();
			m_gameTypes[GAMETYPE_RUSH] = new GameType_Rush();
			
			m_currentGameType = GAMETYPE_NORMAL;
			SetGameType(GAMETYPE_NORMAL);
			
			OnLevelUnLoaded(null);
		}
		
		//----------------------------------------------------------------------------------------------------
		public override function Shutdown()
		{
			
		}
		
		//----------------------------------------------------------------------------------------------------
		public override function OnTick(DeltaTime:Number)
		{
			
		}
		
		//----------------------------------------------------------------------------------------------------
		public function SetEditorMode(editor:Boolean)
		{
			m_editor = editor;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetEditorMode():Boolean
		{
			return m_editor;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function SetGameType(gameType:Number)
		{
			m_gameTypes[m_currentGameType].SetActive(false);
			m_currentGameType = gameType;
			m_gameTypes[m_currentGameType].SetActive(true);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetCurrentGameType():IGameType
		{
			return m_gameTypes[m_currentGameType];
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetCurrentGameTypeID():Number
		{
			return m_currentGameType;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetGameTypes():Array
		{
			return m_gameTypes;
		}
		
		//----------------------------------------------------------------------------------------------------
		// Events
		//----------------------------------------------------------------------------------------------------
		private function RaiseBeginGameEvent()
		{
			m_gEvt = new GameEvent(GameEvent.BEGIN);
			dispatchEvent(m_gEvt);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function RaiseGameUpdateEvent()
		{
			m_gEvt = new GameEvent(GameEvent.GAMETYPE_UPDATE);
			dispatchEvent(m_gEvt);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function EndGame()
		{
			m_gEvt = new GameEvent(GameEvent.END);
			dispatchEvent(m_gEvt);
		}
		
		//----------------------------------------------------------------------------------------------------
		// External Events
		//----------------------------------------------------------------------------------------------------
		public function OnLevelUnLoaded(evt:LevelEvent)
		{
			m_numGoalNodes = 0;
			m_numDocuments = 0;
			m_numNodes = 0;
			m_capMap = new Array();
			m_fateMap = new Array();
			m_docMap = new Array();
			m_killMap = new Array();
		}
		
		//----------------------------------------------------------------------------------------------------
		public function OnLevelLoaded(evt:LevelEvent)
		{
			if (m_editor)
				return;
				
			SetGameType(m_levelManager.GetCurrentLevel().GetGameType());
			
			RaiseBeginGameEvent();
		}
		
		//----------------------------------------------------------------------------------------------------
		public function OnNodeSpawned(evt:NodeEvent)
		{
			if(evt.m_node.GetType() == NodeManager.NODE_GOAL)
				m_numGoalNodes++;
				
			else if(evt.m_node.GetType() == NodeManager.NODE_DOCUMENT)
				m_numDocuments++;
				
			m_numNodes++;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function OnNodeCaptured(evt:NodeEvent)
		{
			if (m_editor)
				return;
				
			m_capMap[evt.m_capBy]++;
			
			switch (evt.m_node.GetType())
			{
				// Root and sentry for player killing -------------------
				case NodeManager.NODE_ROOT:
				case NodeManager.NODE_SENTRY:
				{
					if (evt.m_node.GetOcupants().length <= 1)
					return
				
				var player:Number = m_playerManager.GetPlayerFromRootNode(evt.m_node.GetID());
				if (player == -1)
					return;
					
				m_killMap[evt.m_capBy]++;
				
				DeclarePlayerFate(FATE_DEFEAT, player);
				}break;
				
				// Document node for score keeping -----------------------
				case NodeManager.NODE_DOCUMENT:
				{
					m_docMap[evt.m_capBy]++;
					
					if (evt.m_capBy == m_playerManager.GetCurrentPlayerID())
						m_notificationManager.RaiseNotification("DOWNLOADED DOCUMENT " + m_docMap[evt.m_capBy]);
					
				}break;
			}
		}
		
		//----------------------------------------------------------------------------------------------------
		public function OnPlayerJoin(evt:PlayerEvent)
		{
			if (m_editor)
				return;
				
			m_fateMap[evt.m_playerNumber] = FATE_UNKNOWN;
			m_docMap[evt.m_playerNumber] = 0;
			m_capMap[evt.m_playerNumber] = 1; //Set to one to include root node.
			m_killMap[evt.m_playerNumber] = 0;
		}
		
		//----------------------------------------------------------------------------------------------------
		// External functions
		//----------------------------------------------------------------------------------------------------
		public function GetPlayerFate(playerNumber:Number):Number
		{
			return m_fateMap[playerNumber];
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetPlayerDocs(playerNumber:Number):Number
		{
			return m_docMap[playerNumber];
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetTotalDocs():Number
		{
			return m_numDocuments;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetPlayerCaps(playerNumber:Number):Number
		{
			return m_capMap[playerNumber];
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetTotalNodes():Number
		{
			return m_numNodes;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetPlayerKills(playerNumber:Number):Number
		{
			return m_killMap[playerNumber];
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetTotalSentries():Number
		{
			return (m_playerManager.GetPlayerIDs().length - 2);
		}
		
		//----------------------------------------------------------------------------------------------------
		// Internal functions
		//----------------------------------------------------------------------------------------------------
		public function DeclarePlayerFate(fate:Number, playerID:Number)
		{
			m_fateMap[playerID] = fate;
			
			m_playerManager.RaisePlayerFateEvent(playerID, fate);
			
			if (fate == FATE_DEFEAT)
			{
				if (m_playerManager.GetPlayer(playerID).GetType() == PlayerManager.PLAYER_COMPUTER)
					m_notificationManager.RaiseNotification("SENTRY OFFLINE");
			}
			
			// If someone has won, end the game.
			if (fate == FATE_VICTORY)
				EndGame();
		}
		
		//----------------------------------------------------------------------------------------------------
	}
}